#include "UsuarioSinIdentificar.h"
#include "SocketServer.h"

#include <syslog.h>


// Busco si el usuario ya esta conectado al sistema (mediante otro device)
// o si es la primer instancia de este usuario que se conecta.
void UsuarioSinIdentificar::identificarUser(){

	bool usuarioYaConectado = false;

	users.lock();
	std::list<Usuario*>::iterator iterador = users.begin();
	while (iterador != users.end()){
		if ( ((*iterador)->obtenerNombre() == this->nombre) && ((*iterador)->esIdentificado()) ){
			//TODO: agregar la maquina a este usuario.
			usuarioYaConectado = true;
			(*iterador)->agregarDevice(comunicador, comunicadorNotif);
			syslog( LOG_INFO , "El user ya se hallaba online, agregando nuevo device...");
		};
		++iterador;
	};
	users.unlock();

	if (!usuarioYaConectado) {
		syslog( LOG_INFO , "El user no se hallaba online, agregando user...");
		Usuario * userAux = new Usuario(this->nombre);
		userAux->agregarDevice(comunicador, comunicadorNotif);
		userAux->start();
		users.push_back(userAux);
	}
}

void UsuarioSinIdentificar::inicializarComNotif(){
	// Inicializo el comunicador por el cual se enviaran notificaciones.
	int socketNotif;
	unsigned int port = comunicador->getPeerPort() + 1;
	SocketServer socket;
	socket.setAddr_in(port, NULL);
	int retorno = socket.escucharPuerto(port);
	if (retorno != 0) throw MyException("No se pudo crear el comunicador auxiliar para notificaciones.");;
	struct sockaddr_in clienteAux;

	socketNotif = socket.aceptarCliente(clienteAux, sizeof(clienteAux));
	if (socketNotif == -1)	throw MyException("No se pudo crear el comunicador auxiliar para notificaciones.");
	socket.cerrarSocket();
	comunicadorNotif = new Comunicador(socketNotif);
}

UsuarioSinIdentificar::UsuarioSinIdentificar(int s, ListaUsers & u): Usuario("NoName"), users(u){
	comunicador = new Comunicador(s);
}

UsuarioSinIdentificar::~UsuarioSinIdentificar(){
}

void UsuarioSinIdentificar::run(){
	try{
		// Recibe el primer mensaje del cliente, que deberia ser un pedido
		// de login.
		std::string mensajeRecibido;
		//TODO: abortar si no recibo mensaje.
		if (comunicador->recibirMensaje(mensajeRecibido) == -1) return;

		vector<std::string> vec;
		separarString(mensajeRecibido, ' ', vec);

		// TODO: abortar si recibo un mensaje incorrecto.
		if (vec[0] != LOGINREQUEST) return;

		// Paso al encargado de manejar la logica de login.
		LoginCommand login;
		login.execute(vec[1], vec[2]);

		// Si el login falla, envio el mensaje correspondiente al cliente.
		// En caso contrario, inicializo el usuario correcto.
		// En ambos casos, luego de esto termino el thread.
		if (login.fail()) {
			syslog( LOG_INFO , "Intento de login fallido (usrname: %s, pass: %s).", vec[1].c_str(), vec[2].c_str());
			std::string loginFail(LOGINFAIL);
			comunicador->enviarMensaje(loginFail);
		}
		else {
			syslog( LOG_INFO , "Intento login exitoso (usrname: %s, pass: %s).", vec[1].c_str(), vec[2].c_str());
			std::string loginOK(LOGINOK);
			comunicador->enviarMensaje(loginOK);
			comunicador->setClaveSimetrica(vec[2]);

			inicializarComNotif();

			this->nombre = vec[1];
			identificarUser();
		}
	} catch(std::exception& e){
		std::cout << e.what() << std::endl;
		syslog(LOG_ERR, "El programa se ha cerrado inesperadamente: %s ", e.what());
	}
}
